/**
 * ClientController.h
 *
 *  Created on: 2009-04-17
 *      Author: Jacek Suchowski
 *
 * Implementacja klasy odpowieadająca za zbieranie adresów MAC
 */
#include <iostream>
#include <stdio.h>
#include <netdb.h>
#include <netinet/if_ether.h>
#include <stdlib.h>
#include <map>
#include <string>
#include <cstdio>
#include <pthread.h>
using namespace std;

#include "Log.h"
using namespace tftp_server;
#include "MacCollector.h"

/**
 * Kolekcja w której przechowywane są pary IP i MAC
 */
map<IP, MAC> collection;

MacCollector::MacCollector()
{
	isRunning = false;
}

MacCollector::MacCollector(bool arg)
{
	if (arg == true)
	{
		isRunning = true;
		threadHandle = pthread_create(&threadId, NULL, &runFunc, (void*) this);
		sleep(1);
	}
	else
	{
		isRunning = false;
	}
}

MacCollector::~MacCollector()
{
	//close(sock);
}

void *MacCollector::runFunc(void *self)
{
	MacCollector a;
	a.run();
	return NULL;
}

void MacCollector::run()
{
	int n;
	int sock;
	char buffer[2048];
	unsigned char *iphead, *ethhead;

	char tempMAC[20];
	char tempIP[20];

	char t[200];

	if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) < 0)
	{
		Loger::getInstance().send(Log("MacCollector: unable to create socket!", 1));
	}

		Loger::getInstance().send(Log("MacCollector: start listening!", 3));
	while (1)
	{
		if (n = recvfrom(sock, buffer, 2048, 0, NULL, NULL) == -1)
		{
			Loger::getInstance().send(Log("MacCollector: unable to receivefrom socket!", 2));
			close(sock);
		}

		ethhead = (unsigned char *) buffer;

		if (ethhead != NULL)
		{
			iphead = (unsigned char *) (buffer + 14);
			sprintf(tempMAC, "%02x:%02x:%02x:%02x:%02x:%02x",
					ethhead[6],ethhead[7],ethhead[8],ethhead[9],ethhead[10],ethhead[11]);

			string strMAC(tempMAC);

			if (*iphead == 0x45)
			{
				sprintf(tempIP, "%d.%d.%d.%d", iphead[12], iphead[13],
						iphead[14], iphead[15]);

				string strIP(tempIP);

				addMac(IP(strIP), MAC(strMAC));

			}
		}
	}
}


void MacCollector::addMac(IP ip, MAC mac)
{
	map<IP, MAC>::iterator it = collection.find(ip);

	if (it == collection.end())
	{
		collection.insert(make_pair(ip, mac));
	}
	else
	{
		pair<IP, MAC> t = make_pair(IP(ip), MAC(mac));
		it->second = mac;
	}
}

MAC MacCollector::findMac(IP ip)
{
		map<IP, MAC>::iterator it = collection.find(ip);
		if(isRunning)
		{
			if (it == collection.end())
						{
							Loger::getInstance().send(Log("MacCollector: waiting for MAC!", 3));
							sleep(1);
							it = collection.find(ip);
							if (it == collection.end())
							{
								Loger::getInstance().send(Log("MacCollector: waiting for MAC!", 3));
								sleep(1);
							}
							it = collection.find(ip);
							if (it == collection.end())
								return MAC(" ");
						}
							pair<IP, MAC> t = *it;
							return t.second;
		}
		return MAC(" ");
}

